home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / emacs_src_18_58.lha / emacs-18.58 / src / simplerexx.c < prev    next >
C/C++ Source or Header  |  1992-04-28  |  11KB  |  415 lines

  1. /*
  2.  * Simple ARexx interface by Michael Sinz
  3.  *
  4.  * This is a very "Simple" interface to the world of ARexx...
  5.  * For more complex interfaces into ARexx, it is best that you
  6.  * understand the functions that are provided by ARexx.
  7.  * In many cases they are more powerful than what is presented
  8.  * here.
  9.  *
  10.  * This code is fully re-entrant and self-contained other than
  11.  * the use of SysBase/AbsExecBase and the ARexx RVI support
  12.  * library which is also self-contained...
  13.  */
  14.  
  15. #include    <exec/types.h>
  16. #include    <exec/nodes.h>
  17. #include    <exec/lists.h>
  18. #include    <exec/ports.h>
  19. #include    <exec/memory.h>
  20.  
  21. #include    <proto/exec.h>
  22.  
  23. #include    <rexx/storage.h>
  24. #include    <rexx/rxslib.h>
  25.  
  26. #include    <string.h>
  27. #include    <ctype.h>
  28.  
  29. /*
  30.  * The prototypes for the few ARexx functions we will call...
  31.  */
  32. struct RexxMsg *CreateRexxMsg(struct MsgPort *,char *,char *);
  33. void *CreateArgstring(char *,long);
  34. void DeleteRexxMsg(struct RexxMsg *);
  35. void DeleteArgstring(char *);
  36. BOOL IsRexxMsg(struct Message *);
  37.  
  38. /*
  39.  * Pragmas for the above functions...  (To make this all self-contained...)
  40.  * If you use RexxGlue.o, this is not needed...
  41.  *
  42.  * These are for Lattice C 5.x  (Note the use of RexxContext->RexxSysBase)
  43.  */
  44. #pragma libcall RexxContext->RexxSysBase CreateRexxMsg 90 09803
  45. #pragma libcall RexxContext->RexxSysBase CreateArgstring 7E 0802
  46. #pragma libcall RexxContext->RexxSysBase DeleteRexxMsg 96 801
  47. #pragma libcall RexxContext->RexxSysBase DeleteArgstring 84 801
  48. #pragma libcall RexxContext->RexxSysBase IsRexxMsg A8 801
  49.  
  50. /*
  51.  * Prototypes for the RVI ARexx calls...  (link with RexxVars.o)
  52.  */
  53.  long CheckRexxMsg(struct RexxMsg *);
  54.  long GetRexxVar(struct RexxMsg *,char *,char **);
  55.  long SetRexxVar(struct RexxMsg *,char *,char *,long);
  56.  
  57. /*
  58.  * Now, we have made the pragmas needed, let's get to work...
  59.  */
  60.  
  61. /*
  62.  * A structure for the ARexx handler context
  63.  * This is *VERY* *PRIVATE* and should not be touched...
  64.  */
  65. struct    ARexxContext
  66. {
  67. struct    MsgPort    *ARexxPort;    /* The port messages come in at... */
  68. struct    Library    *RexxSysBase;    /* We will hide the library pointer here... */
  69.     long    Outstanding;    /* The count of outstanding ARexx messages... */
  70.     char    PortName[24];    /* The port name goes here... */
  71.     char    ErrorName[28];    /* The name of the <base>.LASTERROR... */
  72.     char    Extension[8];    /* Default file name extension... */
  73. };
  74.  
  75. #define    AREXXCONTEXT    struct ARexxContext *
  76.  
  77. #include    "SimpleRexx.h"
  78.  
  79. /*
  80.  * This function returns the port name of your ARexx port.
  81.  * It will return NULL if there is no ARexx port...
  82.  *
  83.  * This string is *READ ONLY*  You *MUST NOT* modify it...
  84.  */
  85. char *ARexxName(AREXXCONTEXT RexxContext)
  86. {
  87.     register    char    *tmp=NULL;
  88.  
  89.     if (RexxContext) tmp=RexxContext->PortName;
  90.     return(tmp);
  91. }
  92.  
  93. /*
  94.  * This function returns the signal mask that the Rexx port is
  95.  * using.  It returns NULL if there is no signal...
  96.  *
  97.  * Use this signal bit in your Wait() loop...
  98.  */
  99. ULONG ARexxSignal(AREXXCONTEXT RexxContext)
  100. {
  101.     register    ULONG    tmp=NULL;
  102.  
  103.     if (RexxContext) tmp=1L << (RexxContext->ARexxPort->mp_SigBit);
  104.     return(tmp);
  105. }
  106.  
  107. /*
  108.  * This function returns a structure that contains the commands sent from
  109.  * ARexx or the results of commands you sent.  You will need to parse it 
  110.  * and return the structure back so that the memory can be freed.
  111.  *
  112.  * This returns NULL if there was no message.
  113.  */
  114. struct RexxMsg *GetARexxMsg(AREXXCONTEXT RexxContext)
  115. {
  116.     register    struct    RexxMsg    *tmp=NULL;
  117.     register        short    flag;
  118.  
  119.     if (RexxContext) tmp=(struct RexxMsg *)GetMsg(RexxContext->ARexxPort);
  120.     return(tmp);
  121. }
  122.  
  123. /* Use this to delete a message sent via SendARexxMsg and that has now been
  124.    returned to you.
  125. */
  126. void DeleteARexxMsg(AREXXCONTEXT RexxContext, struct RexxMsg *rmsg)
  127. {
  128.   /*
  129.    * Free the arguments and the message...
  130.    */
  131.   DeleteArgstring(rmsg->rm_Args[0]);
  132.   DeleteRexxMsg(rmsg);
  133.   RexxContext->Outstanding-=1;
  134. }
  135.  
  136. /*
  137.  * Use this to return a ARexx message...
  138.  *
  139.  * If you wish to return something, it must be in the RString.
  140.  * If you wish to return an Error, it must be in the Error.
  141.  * If there is an error, the RString is ignored.
  142.  */
  143. void ReplyARexxMsg(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  144.            char *RString,LONG Error)
  145. {
  146.     if (RexxContext) if (rmsg) if (rmsg!=REXX_RETURN_ERROR)
  147.     {
  148.     rmsg->rm_Result2=0;
  149.     if (!(rmsg->rm_Result1=Error))
  150.     {
  151.         /*
  152.          * if you did not have an error we return the string
  153.          */
  154.         if (rmsg->rm_Action & (1L << RXFB_RESULT)) if (RString)
  155.         {
  156.         rmsg->rm_Result2=(LONG)CreateArgstring(RString,
  157.                                (LONG)strlen(RString));
  158.         }
  159.     }
  160.  
  161.     /*
  162.      * Reply the message to ARexx...
  163.      */
  164.     ReplyMsg((struct Message *)rmsg);
  165.     }
  166. }
  167.  
  168. /*
  169.  * This function will set an error string for the ARexx
  170.  * application in the variable defined as <appname>.LASTERROR
  171.  *
  172.  * Note that this can only happen if there is an ARexx message...
  173.  *
  174.  * This returns TRUE if it worked, FALSE if it did not...
  175.  */
  176. short SetARexxLastError(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
  177.             char *ErrorString)
  178. {
  179.     register    short    OkFlag=FALSE;
  180.  
  181.     if (RexxContext) if (rmsg) if (CheckRexxMsg(rmsg))
  182.     {
  183.     /*
  184.      * Note that SetRexxVar() has more than just a TRUE/FALSE
  185.      * return code, but for this "basic" case, we just care if
  186.      * it works or not.
  187.      */
  188.     if (!SetRexxVar(rmsg,RexxContext->ErrorName,ErrorString,
  189.             (long)strlen(ErrorString)))
  190.     {
  191.         OkFlag=TRUE;
  192.     }
  193.     }
  194.     return(OkFlag);
  195. }
  196.  
  197. /*
  198.  * This function will send a string to ARexx...
  199.  *
  200.  * The default host port will be that of your task...
  201.  *
  202.  * If you set StringFile to TRUE, it will set that bit for the message...
  203.  *
  204.  * Returns the message sent, or NULL in case of error.
  205.  */
  206. struct RexxMsg *SendARexxMsg(AREXXCONTEXT RexxContext,char *RString,
  207.                   short StringFile)
  208. {
  209.     register    struct    MsgPort    *RexxPort;
  210.     register    struct    RexxMsg    *rmsg;
  211.     register        short    flag=FALSE;
  212.  
  213.     if (RexxContext) if (RString)
  214.     {
  215.     if (rmsg=CreateRexxMsg(RexxContext->ARexxPort,
  216.                    RexxContext->Extension,
  217.                    RexxContext->PortName))
  218.     {
  219.         rmsg->rm_Action=RXCOMM | (StringFile ?
  220.                       (1L << RXFB_STRING):0);
  221.         if (rmsg->rm_Args[0]=CreateArgstring(RString,
  222.                          (LONG)strlen(RString)))
  223.         {
  224.         /*
  225.          * We need to find the RexxPort and this needs
  226.          * to be done in a Forbid()
  227.          */
  228.         Forbid();
  229.         if (RexxPort=FindPort(RXSDIR))
  230.         {
  231.             /*
  232.              * We found the port, so put the
  233.              * message to ARexx...
  234.              */
  235.             PutMsg(RexxPort,(struct Message *)rmsg);
  236.             RexxContext->Outstanding+=1;
  237.             flag=TRUE;
  238.         }
  239.         else
  240.         {
  241.             /*
  242.              * No port, so clean up...
  243.              */
  244.             DeleteArgstring(rmsg->rm_Args[0]);
  245.             DeleteRexxMsg(rmsg);
  246.         }
  247.         Permit();
  248.         }
  249.         else DeleteRexxMsg(rmsg);
  250.     }
  251.     }
  252.     return flag ? rmsg : NULL;
  253. }
  254.  
  255. int PendingCommands(AREXXCONTEXT RexxContext)
  256. {
  257.     if (RexxContext) return RexxContext->Outstanding;
  258.     else return 0;
  259. }
  260.  
  261. /*
  262.  * This function closes down the ARexx context that was opened
  263.  * with InitARexx...
  264.  */
  265. void FreeARexx(AREXXCONTEXT RexxContext)
  266. {
  267.     register    struct    RexxMsg    *rmsg;
  268.  
  269.     if (RexxContext)
  270.     {
  271.     /*
  272.      * Clear port name so it can't be found...
  273.      */
  274.     RexxContext->PortName[0]='\0';
  275.  
  276.     /*
  277.      * Clean out any outstanding messages we had sent out...
  278.      */
  279.     while (RexxContext->Outstanding)
  280.     {
  281.         WaitPort(RexxContext->ARexxPort);
  282.         while (rmsg=GetARexxMsg(RexxContext))
  283.         {
  284.         if (rmsg!=REXX_RETURN_ERROR)
  285.         {
  286.             /*
  287.              * Any messages that come now are blown
  288.              * away...
  289.              */
  290.             SetARexxLastError(RexxContext,rmsg,
  291.                       "99: Port Closed!");
  292.             ReplyARexxMsg(RexxContext,rmsg,
  293.                   NULL,100);
  294.         }
  295.         }
  296.     }
  297.  
  298.     /*
  299.      * Clean up the port and delete it...
  300.      */
  301.     if (RexxContext->ARexxPort)
  302.     {
  303.         while (rmsg=GetARexxMsg(RexxContext))
  304.         {
  305.         /*
  306.          * Any messages that still are coming in are
  307.          * "dead"  We just set the LASTERROR and
  308.          * reply an error of 100...
  309.          */
  310.         SetARexxLastError(RexxContext,rmsg,
  311.                   "99: Port Closed!");
  312.         ReplyARexxMsg(RexxContext,rmsg,NULL,100);
  313.         }
  314.         RemPort(RexxContext->ARexxPort);
  315.         DeleteMsgPort(RexxContext->ARexxPort);
  316.     }
  317.  
  318.     /*
  319.      * Make sure we close the library...
  320.      */
  321.     if (RexxContext->RexxSysBase)
  322.     {
  323.         CloseLibrary(RexxContext->RexxSysBase);
  324.     }
  325.  
  326.     /*
  327.      * Free the memory of the RexxContext
  328.      */
  329.     FreeMem(RexxContext,sizeof(struct ARexxContext));
  330.     }
  331. }
  332.  
  333. /*
  334.  * This routine initializes an ARexx port for your process
  335.  * This should only be done once per process.  You must call it
  336.  * with a valid application name and you must use the handle it
  337.  * returns in all other calls...
  338.  *
  339.  * NOTE:  The AppName should not have spaces in it...
  340.  *        Example AppNames:  "MyWord" or "FastCalc" etc...
  341.  *        The name *MUST* be less that 16 characters...
  342.  *        If it is not, it will be trimmed...
  343.  *        The name will also be UPPER-CASED...
  344.  *
  345.  * NOTE:  The Default file name extension, if NULL will be
  346.  *        "rexx"  (the "." is automatic)
  347.  */
  348. AREXXCONTEXT InitARexx(char *AppName,char *Extension)
  349. {
  350.     register    AREXXCONTEXT    RexxContext=NULL;
  351.     register    short        loop;
  352.     register    short        count;
  353.     register    char        *tmp;
  354.  
  355.     if (RexxContext=AllocMem(sizeof(struct ARexxContext),
  356.                  MEMF_PUBLIC|MEMF_CLEAR))
  357.     {
  358.     if (RexxContext->RexxSysBase=OpenLibrary("rexxsyslib.library", NULL))
  359.     {
  360.         /*
  361.          * Set up the extension...
  362.          */
  363.         if (!Extension) Extension="rexx";
  364.         tmp=RexxContext->Extension;
  365.         for (loop=0;(loop<7)&&(Extension[loop]);loop++)
  366.         {
  367.         *tmp++=Extension[loop];
  368.         }
  369.         *tmp='\0';
  370.  
  371.         /*
  372.          * Set up a port name...
  373.          */
  374.         tmp=RexxContext->PortName;
  375.         for (loop=0;(loop<16)&&(AppName[loop]);loop++)
  376.         {
  377.         *tmp++=toupper(AppName[loop]);
  378.         }
  379.         *tmp='\0';
  380.  
  381.         /*
  382.          * Set up the last error RVI name...
  383.          *
  384.          * This is <appname>.LASTERROR
  385.          */
  386.         strcpy(RexxContext->ErrorName,RexxContext->PortName);
  387.         strcat(RexxContext->ErrorName,".LASTERROR");
  388.  
  389.         /* We need to make a unique port name... */
  390.         Forbid();
  391.         for (count=1,RexxContext->ARexxPort=(VOID *)1;
  392.          RexxContext->ARexxPort;count++)
  393.         {
  394.         stci_d(tmp,count);
  395.         RexxContext->ARexxPort=
  396.             FindPort(RexxContext->PortName);
  397.         }
  398.  
  399.         /*RexxContext->ARexxPort=CreatePort(RexxContext->PortName,NULL);*/
  400.         RexxContext->ARexxPort=CreateMsgPort();
  401.         RexxContext->ARexxPort->mp_Node.ln_Name = RexxContext->PortName;
  402.         RexxContext->ARexxPort->mp_Node.ln_Pri = 0;
  403.         AddPort(RexxContext->ARexxPort);
  404.         Permit();
  405.     }
  406.  
  407.     if (!RexxContext->RexxSysBase || !RexxContext->ARexxPort)
  408.     {
  409.         FreeARexx(RexxContext);
  410.         RexxContext=NULL;
  411.     }
  412.     }
  413.     return(RexxContext);
  414. }
  415.